//==============================================================================
#include "Model.h"

static int MAX_MS_EVENT_WAIT = 50;
static int MAX_MS_PROCESS_WAIT = 100;

//==============================================================================
Model::Model(GameServer* server, string sceneName)
{
	lock = new CriticalSection();
	setIsReady(false);
	setIsSceneStateReady(false);
	setServer(server);
	setSceneName(sceneName);
	setScene(new Scene(29,26,sceneName));
}
//------------------------------------------------------------------------------
Model::~Model(void)
{
	delete getScene();
	delete lock;
}
//------------------------------------------------------------------------------
CriticalSection* Model::getAddNewTankLock()
{
	return &this->addNewTankLock;
}
//------------------------------------------------------------------------------
void Model::setScene(Scene* scene)
{
	this->scene = scene;
}
//------------------------------------------------------------------------------
Scene* Model::getScene()
{
	return this->scene;
}
//------------------------------------------------------------------------------
void Model::setSceneName(string name)
{
	this->sceneName = name;
}
//------------------------------------------------------------------------------
string Model::getSceneName()
{
	return this->sceneName;
}
//------------------------------------------------------------------------------
string Model::getSceneBackgroundPath()
{
	return getScene()->getBackgroundPath();
}
//------------------------------------------------------------------------------
void Model::setIsProcessing(bool flag)
{
	this->_isProcessing = flag;
}
//------------------------------------------------------------------------------
bool Model::isProcessing(void)
{
	return this->_isProcessing;
}
//------------------------------------------------------------------------------
void Model::setIsReady(bool flag)
{
	this->_isReady = flag;
}
//------------------------------------------------------------------------------
bool Model::isReady(void)
{
	return _isReady;
}
//------------------------------------------------------------------------------
void Model::setIsSceneStateReady(bool flag)
{
	this->_isSceneStateReady = flag;
}
//------------------------------------------------------------------------------
bool Model::isSceneStateReady(void)
{
	return this->_isSceneStateReady;
}
//------------------------------------------------------------------------------
void Model::setServer(GameServer* server)
{
	this->server = server;
}
//------------------------------------------------------------------------------
GameServer* Model::getServer(void)
{
	return this->server;
}
//------------------------------------------------------------------------------
ByteBuffer* Model::getSceneState(void)
{
	return &this->sceneState;
}
//------------------------------------------------------------------------------
int Model::addNewTank(string name)
{
//Crea un nuevo tanque y devuelve el id
	getAddNewTankLock()->adquire();
	srand(time(NULL)); 
	int id = -1;
	int posx,posy;
	Tank* newTank = new Tank();
	newTank->setName(name);
	newTank->loadSurface();
	while(id < 0)
	{
		posx = getScene()->getXCoordinate() + rand() % (getScene()->getXCoordinate() + 800 +1 - getScene()->getXCoordinate()) ;
		posy = getScene()->getYCoordinate() + rand() % (getScene()->getYCoordinate() + 600 +1 - getScene()->getYCoordinate()) ;
		newTank->setXCoordinate(posx);
		newTank->setYCoordinate(posy);
		id =  getScene()->addTank(newTank);
	}
	getAddNewTankLock()->release();
	return id;
}
//------------------------------------------------------------------------------
void Model::loadSceneGameFiles()
{
	SceneRepository sceneRepo;
	try
	{
		sceneRepo.load(getSceneName(),getScene());
		try
		{
			scene->loadSurface();
		}
		catch (SDL_Exception &ex)
		{
			Log::getInstance()->error("[SERVER] SDL_Exception loading XML: " +  ex.getMessage() + " ; " + SDL_GetError());
		}

		Log::getInstance()->info("[SERVER] Scene GameFiles load successfully!");

	}
	catch (PersistenceException& pe)
	{
		Log::getInstance()->error("[SERVER] PersistenceException loading XML: " +  pe.getMessage());
	}
}
//------------------------------------------------------------------------------
DWORD Model::run(void)
{
	return startProcessingUpdates();
}
//------------------------------------------------------------------------------
int Model::startProcessingUpdates(void)
{
	loadSceneGameFiles();
	setIsReady(true);
	ByteBuffer sendBuffer;
	HRTimer timer;
	double timeElapsed;
	while(isProcessing()){
		timeElapsed = 0;
		setIsSceneStateReady(false);
		timer.startTimer();
		while(!getServer()->getNewGameEvents()->empty() || timeElapsed < MAX_MS_EVENT_WAIT)
		{
			if(!getServer()->getNewGameEvents()->empty())
			{
				getServer()->getNewGameEventsLock()->adquire();
				GameEvent* gameEvent = getServer()->getNewGameEvents()->front();
				getServer()->getNewGameEvents()->pop();
				getServer()->getNewGameEventsLock()->release();
				getScene()->handleGameEvent(gameEvent);
				delete gameEvent;
			}
			timer.stopTimer();
			timeElapsed += timer.getElapsedTime() * 1000;
		}

		//	//Mover objetosde la escena
		list<ui::SceneObject*>::iterator it1 = getScene()->getObjsLst()->begin();
		while( it1 != getScene()->getObjsLst()->end() && !( getScene()->getObjsLst()->empty() ) )
		{	
			if(!(*it1)->getAlive())
			{
				list<ui::SceneObject*>::iterator newIt = it1;
				it1++;
				delete (*newIt);
				getScene()->getObjsLst()->erase(newIt);


			}else{
			(*it1)->rotate();
			(*it1)->move(getScene());
			
			
			it1++;}
		}
		//delete this->sceneState;
		getScene()->marshal(&this->sceneState);
		setIsSceneStateReady(true);
		Message message(SCENE_STATE,getServer()->getModel()->getSceneState()->getAll());
		list <SessionHandler*>::iterator it2 = getServer()->getSessionsLst()->begin();
		while(it2 != getServer()->getSessionsLst()->end())
		{
			if((*it2)->isReady())
			{
				try
				{
					message.marshal(&sendBuffer);
					(*it2)->getClientSocket()->doSendComplete(&sendBuffer);
				}
				catch (NetworkException& ne)
				{
				}	
			}
			it2++;
		}
		timer.stopTimer();
		timeElapsed += timer.getElapsedTime() * 1000;
		if(timeElapsed < MAX_MS_PROCESS_WAIT)
			Sleep(MAX_MS_PROCESS_WAIT - timeElapsed);
	}
	return 0;
}
//------------------------------------------------------------------------------
void Model::stopProcessingUpdates(void)
{
	setIsProcessing(false);
	setIsReady(false);
}


